﻿using System;

public class Mapper105 : MapperDefault
{
    internal int bits;
    private int init_state;
    private int irq_counter;
    private bool irq_enabled;
    private int[] regs = new int[4];
    internal int write_count;

    public override void init(NES nes)
    {
        base.init(nes);
        this.reset();
    }

    public override void loadROM(ROM rom)
    {
        if (rom.Valid)
        {
            this.load8kRomBank(0, 0x8000);
            this.load8kRomBank(1, 0xa000);
            this.load8kRomBank(2, 0xc000);
            this.load8kRomBank(3, 0xe000);
            this.loadCHRROM();
            base.nes.Cpu.requestIrq(2);
        }
    }

    public override void mapperInternalStateLoad(ByteBuffer buf)
    {
        base.mapperInternalStateLoad(buf);
        if (buf.readByte() == 1)
        {
            this.irq_counter = buf.readInt();
            this.irq_enabled = buf.readBoolean();
            this.init_state = buf.readInt();
        }
    }

    public override void mapperInternalStateSave(ByteBuffer buf)
    {
        base.mapperInternalStateSave(buf);
        buf.putByte(1);
        buf.putInt(this.irq_counter);
        buf.putBoolean(this.irq_enabled);
        buf.putInt(this.init_state);
    }

    public override void reset()
    {
        this.regs[0] = 12;
        this.regs[1] = 0;
        this.regs[2] = 0;
        this.regs[3] = 0x10;
        this.bits = 0;
        this.write_count = 0;
        this.irq_enabled = false;
        this.irq_counter = 0;
        this.init_state = 0;
    }

    public override int syncH(int scanline)
    {
        if (scanline == 0)
        {
            if (this.irq_enabled)
            {
                this.irq_counter += 0x7455;
            }
            if (((this.irq_counter | 0x21ffffff) & 0x3e000000) == 0x3e000000)
            {
                return 3;
            }
        }
        return 0;
    }

    public override void write(int address, short value_Renamed)
    {
        int index = (address & 0x7fff) >> 13;
        if (address < 0x8000)
        {
            base.write(address, value_Renamed);
        }
        else
        {
            if ((value_Renamed & 0x80) != 0)
            {
                this.bits = 0;
                this.write_count = 0;
                if (index == 0)
                {
                    this.regs[index] |= 12;
                }
            }
            else
            {
                this.bits |= (value_Renamed & 1) << this.write_count++;
                if (this.write_count == 5)
                {
                    this.regs[index] = this.bits & 0x1f;
                    this.bits = this.write_count = 0;
                }
            }
            if ((this.regs[0] & 2) != 0)
            {
                if ((this.regs[0] & 1) != 0)
                {
                    base.nes.Ppu.Mirroring = 1;
                }
                else
                {
                    base.nes.Ppu.Mirroring = 0;
                }
            }
            else if ((this.regs[0] & 1) != 0)
            {
                base.nes.Ppu.Mirroring = 4;
            }
            else
            {
                base.nes.Ppu.Mirroring = 3;
            }
            switch (this.init_state)
            {
                case 0:
                case 1:
                    this.init_state++;
                    return;

                case 2:
                    if ((this.regs[1] & 8) == 0)
                    {
                        this.load8kRomBank((this.regs[1] & 6) * 2, 0x8000);
                        this.load8kRomBank(((this.regs[1] & 6) * 2) + 1, 0xa000);
                        this.load8kRomBank(((this.regs[1] & 6) * 2) + 2, 0xc000);
                        this.load8kRomBank(((this.regs[1] & 6) * 2) + 3, 0xe000);
                        break;
                    }
                    if ((this.regs[0] & 8) == 0)
                    {
                        this.load8kRomBank(((this.regs[3] & 6) * 2) + 0x10, 0x8000);
                        this.load8kRomBank(((this.regs[3] & 6) * 2) + 0x11, 0xa000);
                        this.load8kRomBank(((this.regs[3] & 6) * 2) + 0x12, 0xc000);
                        this.load8kRomBank(((this.regs[3] & 6) * 2) + 0x13, 0xe000);
                        break;
                    }
                    if ((this.regs[0] & 4) == 0)
                    {
                        this.load8kRomBank(0x10, 0x8000);
                        this.load8kRomBank(0x11, 0xa000);
                        this.load8kRomBank(((this.regs[3] & 7) * 2) + 0x10, 0xc000);
                        this.load8kRomBank(((this.regs[3] & 7) * 2) + 0x11, 0xe000);
                        break;
                    }
                    this.load8kRomBank(((this.regs[3] & 7) * 2) + 0x10, 0x8000);
                    this.load8kRomBank(((this.regs[3] & 7) * 2) + 0x11, 0xa000);
                    this.load8kRomBank(30, 0xc000);
                    this.load8kRomBank(0x1f, 0xe000);
                    break;

                default:
                    return;
            }
            if ((this.regs[1] & 0x10) != 0)
            {
                this.irq_counter = 0;
                this.irq_enabled = false;
            }
            else
            {
                this.irq_enabled = true;
            }
        }
    }
}

